#ifndef LIBLPA_H
#define LIBLPA_H

/* TODO:
 * - Find the size at wich forking with OpenMP is faster than doing it with SSE instructions;
 * - Alignment? _aligned_malloc?
 * - Unroll the loop for 8 XMM registers (or 16 in 64 bits)
 * - Check to buffer everything in L1/L2 cache
 * - stream_load?
 * - bench div_ps vs (rcp_ps + mul_ps) vs libdivide
 * - -mavx(2)
 * - Detect SSE/AVX support (cpuid?)
 * - handle not-multiple-of-128-bit array size
 * - Launch exception on division by zero?
 */

#define LPA_FLOAT 0x100
#define LPA_UNSIGNED 0x200

/*
 * Arithmetic section
 */

void lpaAdd(void *restrict left, void *restrict right, unsigned int size, unsigned short vartype);
void lpaAbs(void *restrict left, unsigned int size, unsigned short vartype);
void lpaSub(void *restrict left, void *restrict right, unsigned int size, unsigned short vartype);
void lpaMul(void *restrict left, void *restrict right, unsigned int size, unsigned short vartype);
void lpaRcp(void *restrict left, unsigned int size, unsigned short vartype);
void lpaDiv(void *restrict left, void *restrict right, unsigned int size, unsigned short vartype);
void lpaSqrt(void *restrict left, unsigned int size, unsigned short vartype);

/*
 * Logical section
 */
void lpaNot(void *restrict left, unsigned int size, unsigned short vartype);
void lpaAnd(void *restrict left, void *restrict right, unsigned int size, unsigned short vartype);
void lpaAndNot(void *restrict left, void *restrict right, unsigned int size, unsigned short vartype);
void lpaOr(void *restrict left, void *restrict right, unsigned int size, unsigned short vartype);
void lpaXOr(void *restrict left, void *restrict right, unsigned int size, unsigned short vartype);
char lpaCmp(void *restrict left, void *restrict right, unsigned int size, unsigned short vartype);
void lpaFullCmp(void *restrict left, void *restrict right, unsigned int size, unsigned short vartype);

/*
 * Conversion section
 */
void lpaFtoF(void *restrict left, unsigned int size, unsigned short leftvartype, unsigned short rightvartype);
void lpaFtoI(void *restrict left, unsigned int size, unsigned short leftvartype, unsigned short rightvartype);
void lpaItoF(void *restrict left, unsigned int size, unsigned short leftvartype, unsigned short rightvartype);
void lpaItoI(void *restrict left, unsigned int size, unsigned short leftvartype, unsigned short rightvartype);

/*
 * Reduce section
 */
void lpaSum(void *restrict left, unsigned int size, unsigned short vartype);
void lpaMin(void *restrict left, unsigned int size, unsigned short vartype);
void lpaMax(void *restrict left, unsigned int size, unsigned short vartype);
void lpaAvg(void *restrict left, unsigned int size, unsigned short vartype);
void lpaDotProduct(void *restrict left, void *restrict right, unsigned int size, unsigned short vartype);


/*
 * High-level section
 */

void lpaConvolution(void *restrict left, void *restrict right, unsigned int sizeleft, unsigned int sizeright, unsigned short vartype);
//void lpaFourierTransform(void *restrict input, void *restrict output, unsigned int size, unsigned short vartype);

#endif
